using System;
using System.Collections.Generic;
using System.Text;
using Accountability4net;
using Accountability4net.Contact;

namespace Accountability4net.MemoryMonengineProvider
{
    public class MemoryMonengineProvider: MonengineProviderBase
    {
        Dictionary<int, IAccount> accounts_;
        List<ITransaction> transactions_;
        Dictionary<Guid, IContact> contacts_;

        public MemoryMonengineProvider()
            :base()
        {
            accounts_ = new Dictionary<int, IAccount>();
            transactions_ = new List<ITransaction>();
            contacts_ = new Dictionary<Guid, IContact>();
        }

        public override void Install()
        {
            accounts_ = new Dictionary<int, IAccount>();
            transactions_ = new List<ITransaction>();
            contacts_ = new Dictionary<Guid, IContact>();
        }

        public override IAccount CreateAccount(int number, AccountType type)
        {
            IAccount account = new MemoryAccount(number, type);
            accounts_.Add(number, account);
            return account;
        }

        public override IAction CreateAction(ActionType type, IAccount account, decimal amount)
        {
            return new BaseAction(type, account, amount);
        }

        public override ITransaction CreateTransaction(DateTimeOffset timestamp)
        {
            ITransaction transaction = new MemoryTransaction(timestamp);
            transactions_.Add(transaction);
            return transaction;
        }

        public override IAccount GetAccount(int number)
        {
            return accounts_[number];
        }

        public override IList<IAccount> GetAccounts(int from, int limit)
        {
            Dictionary<int, IAccount>.KeyCollection accountNumbers = accounts_.Keys;
            List<IAccount> accounts = new List<IAccount>();
            foreach (int number in accountNumbers)
            {
                if (number >= from)
                {
                    if (limit-- > 0)
                    {
                        accounts.Add(accounts_[number]);
                    }
                }
            }
            return accounts;
        }

        public override IList<ITransaction> GetTransactions()
        {
            return transactions_.FindAll(
                delegate(ITransaction transaction)
                {
                    return transaction.IsCommitted;
                }
            );
        }

        public override IList<ITransaction> GetTransactions(IAccount account)
        {
            List<ITransaction> transactions = new List<ITransaction>(GetTransactions());
            return transactions.FindAll(
                    delegate(ITransaction transaction)
                    {
                        foreach (IAction action in transaction)
                        {
                            if (action.Account.Number == account.Number)
                            {
                                return true;
                            }
                        }
                        return false;
                    }
                );
        }

        public override IList<ITransaction> GetTransactions(IAccount account, DateTimeOffset? after)
        {
            List<ITransaction> transactions = new List<ITransaction>(GetTransactions(account));
            if(after.HasValue)
            {
                return transactions.FindAll(
                    delegate(ITransaction transaction)
                    {
                        return transaction.Timestamp.UtcTicks >= after.Value.UtcTicks;
                    }
                );
            }
            else
            {
                return transactions;
            }
        }

        public override IList<ITransaction> GetTransactions(IAccount account, DateTimeOffset? after, DateTimeOffset? before)
        {
            List<ITransaction> transactions = new List<ITransaction>(GetTransactions(account, after));
            if (before.HasValue)
            {
                return transactions.FindAll(
                    delegate(ITransaction transaction)
                    {
                        return transaction.Timestamp.UtcTicks < before.Value.UtcTicks;
                    }
                );
            }
            else
            {
                return transactions;
            }
        }

        public override void Dispose()
        {
            // No operation
        }


        public override IContact CreateContact()
        {
            IContact contact = new BaseContact();
            contact.ID = Guid.NewGuid();
            contacts_.Add(contact.ID, contact);
            return contact;
        }

        public override IContact GetContact(Guid id)
        {
            IContact contact = null;
            contacts_.TryGetValue(id, out contact);
            return contact;
        }
    }
}
